import os

import numpy as np
import pandas as pd
from show import Show
from config import Define
from datetime import datetime, timedelta


# 将时间字符串转换为numpy.datetime64格式
def convert_to_datetime64(ts_str):
    return np.datetime64(datetime.strptime(ts_str, "%Y-%m-%dT%H:%M:%S.%f"))


class ProcessEvent:
    def __init__(self, config_data):
        self.config_data = config_data
        self.format_str = self.config_data["format_str"]
        self.gantry_info = self.config_data["gantry_info"]
        self.log_path = self.config_data["log_path"]
        self.info = self.config_data["gantry_info"]["info"]
        self.csv_path = None
        self.png_path = None
        self.down_data = None
        self.up_data = None
        self.all_data = []
        self.abnormal_data = []
        self.show = None

    def init(self):
        self.csv_path = os.path.join(self.log_path, self.info + ".csv")
        self.png_path = os.path.join(self.log_path, "PNG")
        if not os.path.exists(self.png_path):
            os.mkdir(self.png_path)
        self.show = Show(self.png_path)

    def match(self, up_data, down_data):
        all_data = []
        # 创建下行数据的映射，以车牌号为键
        down_map = {}
        for down in down_data:
            plate = down[Define["PLATE"]]
            if plate not in down_map:
                down_map[plate] = [down]
            else:
                down_map[plate].append(down)
        for up in up_data:
            plate = up[Define["PLATE"]]
            if plate in down_map and down_map[plate]:  # 确保有可用的下行记录
                up_time = datetime.strptime(up[Define["TIME"]], self.format_str)
                valid_downs = down_map[plate]
                valid_downs.sort(key=lambda x: datetime.strptime(x[Define["TIME"]], self.format_str))  # 按时间排序

                found_valid_down = False
                for down in valid_downs:
                    down_time = datetime.strptime(down[Define["TIME"]], self.format_str)
                    drive_time = (down_time - up_time).total_seconds()
                    if drive_time >= 0:
                        data = {
                            "up_time": up_time,
                            "down_time": down_time,
                            "drive_time": drive_time,
                            "plate": plate,
                            "type": up[Define["TYPE"]]
                        }
                        all_data.append(data)
                        found_valid_down = True
                        break  # 找到一个有效的下行记录后退出循环

                if found_valid_down:
                    # 移除已经使用过的下行记录
                    while valid_downs and (datetime.strptime(valid_downs[0][Define["TIME"]], self.format_str) <= up_time):
                        del valid_downs[0]

        # all_data.sort(key=lambda x: x["up_time"])  # 按上游出现时间排序
        return all_data

    def remove_abnormal_data(self, all_data):
        drive_time_list = [item["drive_time"] for item in self.all_data]
        mean_time = np.mean(drive_time_list)
        for data in all_data:
            if data["drive_time"] >= (mean_time * 10):
                self.abnormal_data.append(data)
            else:
                self.all_data.append(data)
        # 按上游出现时间排序
        self.all_data.sort(key=lambda x: x["up_time"])

    def get_flow(self, window_size):
        all_data = self.all_data.copy()
        # 将数据转换为DataFrame
        df = pd.DataFrame(all_data)
        grouped_up = df.groupby(pd.Grouper(key="up_time", freq=window_size)).agg(
            total_count=('up_time', 'size'),  # 总记录数
            valid_count=('up_time', 'count')  # 非空记录数
        ).reset_index()
        result_up = grouped_up.reset_index()
        up_dict = result_up.to_dict(orient='records')
        grouped_down = df.groupby(pd.Grouper(key="down_time", freq=window_size)).agg(
            total_count=('down_time', 'size'),  # 总记录数
            valid_count=('down_time', 'count')  # 非空记录数
        ).reset_index()
        result_down = grouped_down.reset_index()
        down_dict = result_down.to_dict(orient='records')

        return up_dict, down_dict

    def get_mean_speed(self, window_size):
        data = self.all_data.copy()
        # all_data = [item for item in data if item["type"] == "1"]
        all_data = [item for item in data]
        # 将数据转换为DataFrame
        df = pd.DataFrame(all_data)
        # 计算每条记录的速度
        df["speed"] = df["drive_time"].apply(lambda x: self.gantry_info["dist"] / x if x > 0 else 0)
        # 设置下时间戳为索引并确保它是datetime类型
        df.set_index(pd.to_datetime(df["up_time"]), inplace=True)

        # 定义一个自定义函数来计算慢行数量
        def count_slow(speeds, avg_speed):
            threshold = avg_speed * 1.2
            return (speeds < threshold).sum()
        # 按照 type 分组，并在每个时间窗口内计算平均速度和其他统计信息
        result = df.groupby(['type', pd.Grouper(freq=window_size)]).agg(
            avg_speed=('speed', 'mean'),
            max_speed=('speed', 'max'),  # 最大速度
            min_speed=('speed', 'min'),  # 最小速度
            count=('speed', 'count'),  # 统计每个窗口内的记录数量
            slow_count=('speed', lambda speeds: count_slow(speeds, speeds.mean()))  # 慢行数量
        ).reset_index()
        # 如果某些时间窗口没有数据，可以通过重采样填充这些窗口

        # 转换为字典（列表记录格式）
        car_mean_speed = result.to_dict(orient='records')

        return car_mean_speed

    def get_car_pass_rate(self, window_size, seconds_average):
        all_data = self.all_data.copy()
        # 将数据转换为DataFrame
        df = pd.DataFrame(all_data)
        # 根据时间间隔分组，并计算平均速度和其他统计信息
        result = df.groupby(pd.Grouper(key="up_time", freq=window_size)).apply(lambda x: pd.Series({
            "valid_count": ((x["drive_time"] <= seconds_average) & (x["drive_time"].notna())).sum(),
            "total_count": len(x),
            "percentage": (((x["drive_time"] <= seconds_average) &
                            (x["drive_time"].notna())).sum() / len(x) * 100) if len(x) > 0 else 100})
        ).reset_index()

        # 转换为字典（列表记录格式）
        car_pass_time = result.to_dict(orient='records')

        return car_pass_time

    def get_all_pass_time(self):
        duration_list = []
        all_data = self.all_data.copy()
        for data in all_data:
            data_dict = {
                "plate": data["plate"],
                "down_time": data["up_time"],
                "type": data["type"],
                "drive_time": data["drive_time"]
            }
            duration_list.append(data_dict)

        return duration_list

    def run(self, up_data, down_data, save_flag=False, show_flag=False):
        all_data = self.match(up_data, down_data)
        if not all_data:
            return
        self.remove_abnormal_data(all_data)
        # 定义时间窗口大小（5分钟）
        window_size = '5T'  # T 表示分钟
        # 上下游门架流量
        up_flow, down_flow = self.get_flow(window_size)
        # 小客车平均速度
        car_mean_speed = self.get_mean_speed(window_size)
        # 小客车通过率
        car_pass_rate = self.get_car_pass_rate(window_size, float(self.gantry_info["car_pass_time"]) * 60)
        # 所有车通过时间
        duration_list = self.get_all_pass_time()

        # 设置显示或保存标识
        self.show.get_setting(save=save_flag, show=show_flag)
        # 显示/保存图表
        # 小车平均速度
        self.show.show_car_mean_speed(car_mean_speed)
        # 小车通过率
        self.show.show_car_pass_rate(car_pass_rate)
        # 小客车通行时间
        self.show.show_car_pass_time(duration_list, ty=True)
        # 各车型通行时间
        self.show.show_car_pass_time(duration_list, ty=False)


def process_main(config_data, up_data, down_data):
    process_event = ProcessEvent(config_data)
    process_event.init()
    process_event.run(up_data, down_data)
